package com.rawchen.config;

import com.rawchen.service.LoginLogService;
import com.rawchen.service.impl.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @Description: Spring Security配置类
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
	private final UserServiceImpl userService;
	private final LoginLogService loginLogService;
	private final MyAuthenticationEntryPoint myAuthenticationEntryPoint;
	private final AuthenticationConfiguration authenticationConfiguration;

	public SecurityConfig(UserServiceImpl userService, LoginLogService loginLogService,
	                      MyAuthenticationEntryPoint myAuthenticationEntryPoint, AuthenticationConfiguration authenticationConfiguration) {
		this.userService = userService;
		this.loginLogService = loginLogService;
		this.myAuthenticationEntryPoint = myAuthenticationEntryPoint;
		this.authenticationConfiguration = authenticationConfiguration;
	}

	@Bean
	public BCryptPasswordEncoder bCryptPasswordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		return http
				//禁用 csrf 防御
				.csrf().disable()
				// 自定义身份验证
				.userDetailsService(userService)
				//开启跨域支持
				.cors().and()
				//基于Token，不创建会话
				.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
				.authorizeHttpRequests()
				//放行获取网页标题后缀的请求
				.requestMatchers("/admin/webTitleSuffix").permitAll()
				//任何 /admin 开头的路径下的请求都需要经过JWT验证
				.requestMatchers(HttpMethod.GET, "/admin/**").hasAnyRole("admin", "visitor")
				.requestMatchers("/admin/**").hasRole("admin")
				//其它路径全部放行
				.anyRequest().permitAll()
				.and()
				//后台登录过滤器，处理后台登录请求
				.addFilterBefore(new JwtLoginFilter("/admin/login", authenticationConfiguration.getAuthenticationManager(), loginLogService), UsernamePasswordAuthenticationFilter.class)
				// 认证过滤器
				.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class)
				//未登录时，返回json，在前端执行重定向
				.exceptionHandling().authenticationEntryPoint(myAuthenticationEntryPoint)
				.and().build();
	}
}
